package Twitim::Twitter;

use strict;
use warnings;

use AnyEvent;
use HTML::Entities;
use JSON::XS;
use POSIX qw(_exit);
use IO::Handle;
# use Data::Dumper;

use Twitim::API::Base;
use base qw(Twitim::NetBase);

my @Twitter_Api   = (
    [ "Timeline",        "_Timeline",        "friends_timeline" ],
    [ "Replies",         "_Replies",         "replies" ],
    [ "Direct Messages", "_Direct Messages", "direct_messages" ],
    [ "Favorites",       "_Favorites",       "favorites" ],
    [ "Following",       "Follow_ing",       "friends" ],
    [ "Followers",       "Follow_ers",       "followers" ]
);

sub new {
    my $this  = shift;
    my $class = ref($this) || $this;
    my $self  = { twitter_url => 'http://twitter.com/', debug => 0, @_ };
    bless $self, $class;

    $self->{'protocol'} = 'Twitter API';
    $self->{'max_message_id'} ||= 0;
    $self->{'message_count'}  ||= 0;
    $self->{'max_dm_id'}      ||= 0;
    $self->{'cb'}->{'message'} ||= sub { $self->_message(@_) };
    $self->{'cb'}->{'error'}   ||= sub { $self->_error(@_) };
    $self->{'delay'}           ||= 0;
    $self->{'dm_interval'}     ||= 6; # percentage
    $self->{'include_web_msg'} ||= 0;

    $self->rate_limit_status;
    Twitim::NetBase->set_my_id( $self->{'userid'} ) if $self->{'userid'};

    return $self;
}

# Status Methods

sub friends_timeline {
    my ( $self, $output ) = @_;

    # FIXME: error check only here
    if (   ! $self->{'userid'}
        || ! $self->{'access_token'}
        || ! $self->{'access_secret'} )
    {
        $self->set_error( $self->_l10n('No account is configured') );
        return;
    } else {
        $self->set_error()
    }

    use Twitim::API::HomeTimeline;
    my $obj = Twitim::API::HomeTimeline->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},

        cb       => { message => $self->{'cb'}->{'message'} },

        delay          => $self->{'delay'},
        interval       => $self->_get_interval('not dm'),
        max_message_id => $self->{'max_message_id'},

        account_obj => $self,
    );
    $obj->get($output);
}

sub user_timeline {
    my ( $self, $username, $output, $num ) = @_;

    use Twitim::API::UserTimeline;
    my $obj = Twitim::API::UserTimeline->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
        cb       => { message => $self->{'cb'}->{'message'} }
    );
    $obj->get( $output, undef, $username, $num );
}

sub update {
    my ( $self, $string, $reply_id ) = @_;

    use Twitim::API::Update;
    my $obj = Twitim::API::Update->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
    );
    $obj->get( $string, $reply_id );
}

sub retweet {
    my ( $self, $id ) = @_;

    use Twitim::API::Retweet;
    my $obj = Twitim::API::Retweet->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
    );
    $obj->get($id);
}

sub replies {
    my ( $self, $output ) = @_;

    use Twitim::API::Replies;
    my $obj = Twitim::API::Replies->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
        cb       => { message => $self->{'cb'}->{'message'} }
    );
    $obj->get($output);
}

# User Methods

sub friends {
    my ( $self, $output ) = @_;

    use Twitim::API::Friends;
    my $obj = Twitim::API::Friends->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
        cb       => { message => $self->{'cb'}->{'message'} }
    );
    $obj->get($output);

}

sub followers {
    my ( $self, $output ) = @_;

    use Twitim::API::Followers;
    my $obj = Twitim::API::Followers->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
        cb       => { message => $self->{'cb'}->{'message'} }
    );
    $obj->get($output);
}

sub show_user {    # not ok
    my ( $self, $userid ) = @_;

    #$self->_getfromapi( 'users/show', "/$userid.json" );

    use Twitim::API::ShowUsers;
    my $obj = Twitim::API::ShowUsers->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
    );
    $obj->get($userid);

}

# Direct Message Methods

sub direct_messages {
    my ( $self, $output ) = @_;

    use Twitim::API::DirectMessages;
    my $obj = Twitim::API::DirectMessages->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
        max_dm_id => $self->{'max_dm_id'},
        cb       => { message => $self->{'cb'}->{'message'} }
    );
    $obj->get($output);
}

# Social Graph Methods

sub followers_ids {    # not
    my $self = shift;

    use Twitim::API::FollowersIDs;
    my $obj = Twitim::API::FollowersIDs->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
    );
    $obj->get();
}

# Account Methods

sub rate_limit_status {
    my $self = shift;

    use Twitim::API::RateLimitStatus;
    my $obj = Twitim::API::RateLimitStatus->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
        account_obj => $self,
    );
    $obj->get();
}

sub get_hourly_limit {
    my $self = shift;
    return $self->{'hourly_limit'};
}

# Favorite Methods

sub favorites {
    my ( $self, $output ) = @_;

    use Twitim::API::Favorites;
    my $obj = Twitim::API::Favorites->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
        cb       => { message => $self->{'cb'}->{'message'} }
    );
    $obj->get($output);
}

sub create_favourings {
    my ( $self, $id ) = @_;

    use Twitim::API::FavoritesCreate;
    my $obj = Twitim::API::FavoritesCreate->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
        cb       => { message => $self->{'cb'}->{'message'} }
    );
    $obj->get($id);
}

sub destroy_favourings {
    my ( $self, $id ) = @_;

    use Twitim::API::FavoritesDestroy;
    my $obj = Twitim::API::FavoritesDestroy->new(
        userid   => $self->{'userid'},
        password => $self->{'password'},
        access_token  => $self->{'access_token'},
        access_secret => $self->{'access_secret'},
        cb       => { message => $self->{'cb'}->{'message'} }
    );
    $obj->get($id);
}

# etc

sub get_message_count {
    my $self   = shift;
    my $result = $self->{'message_count'};

    $self->{'message_count'} = 0; # reset counter
    return $result;
}

sub get_max_message_id {
    my $self = shift;
    return $self->{'max_message_id'};
}

sub get_api_array {
    my $self = shift;
    return @Twitter_Api;
}

sub get_api_names {
    my $self = shift;
    my @api_names;

    foreach my $key (@Twitter_Api) {
        push @api_names, $key->[0];
    }

    return @api_names;
}

sub name2api {
    my ( $self, $name ) = @_;
    my $api;

    foreach my $key (@Twitter_Api) {
        if ( $key->[0] eq $name ) {
            $api = $key->[2];
            last;
        }
    }

    return $api;
}

sub set_delay {
    my ( $self, $arg ) = @_;
    $self->{'delay'} = $arg;
}

sub set_access_timer {
    my ( $self, $api, $old_interval ) = @_;
    $old_interval ||= 60;

    my $twitter_message_count = $self->get_message_count;
    my $xmpp_message_count
        = %Twitim::XMPP::
        ? Twitim::XMPP->get_message_count
        : 0;

    my $diff = my $old_diff = $twitter_message_count - $xmpp_message_count;
    my $min_interval = $self->_get_interval($api);
    my $max_interval = 300;

    $diff-- if $diff <= 0;
    my $interval -= int( 10 * $diff * $old_interval / 60 );
    $interval = $max_interval if $interval > $max_interval;
    $interval = $min_interval if $interval < $min_interval;

    if ( $self->{debug} ) {
        printf "uniq: %d - %d (%d), interval: %d\n",
            $twitter_message_count, $xmpp_message_count, $old_diff, $interval;
    }

    $self->{'timer'} = AnyEvent->timer(
        after => $interval,
        cb    => sub {
            $self->$api;
            $self->set_access_timer( $api, $interval );
        }
    );
}

sub set_dm_timer {
    my ( $self, $api, $old_interval ) = @_;
    my $interval = $self->_get_interval($api);

    $self->{'dm_timer'} = AnyEvent->timer(
        after => $interval,
        cb    => sub {
            $self->$api;
            $self->set_dm_timer( $api, $interval );
        }
    );
}

sub _get_interval {
    my ( $self, $api ) = @_;

    my $percentage
        = $api eq 'direct_messages'
        ? $self->{'dm_interval'}
        : 85 - $self->{'dm_interval'};

    my $hourly_limit = $self->get_hourly_limit || 70;
    my $interval = int( 3600 / $hourly_limit / $percentage * 100 );

    return $interval;
}

1;
